<template>
  <div>
    <el-row @mouseleave="moveTableOutside">
      <el-table
        class="drag_table"
        :cell-class-name="cellClassName"
        :header-cell-class-name="headerCellClassName"
        :data="data"
        :header-cell-style="{
          'background-color': '#E6E9EF',
          color: '#777C7C',
          'font-weight': '400',
          'font-size': '15px',
          'border-right': '1px solid #ffffff'
        }"
        @select="handleSelect"
        @select-all="handleSelectAll"
        @selection-change="handleSelectionChange"
        @header-dragend="handleColumnChange"
        :cell-style="cellStyleFunc"
        size="mini"
        :border="true"
        style="width: 100%"
        stripe
      >
        <el-table-column v-if="selected" type="selection" width="40"> </el-table-column>
        <el-table-column
          type="index"
          label="序号"
          :index="getIndex"
          fixed
          width="60"
          align="center"
        >
        </el-table-column>
        <el-table-column
          v-if="operation.length > 0"
          fixed
          label="操作"
          :width="operation.length * 40 + 60"
          align="center"
        >
          <template slot-scope="scope">
            <template v-for="(item, index) in operation">
              <div
                :key="index"
                style="display: inline"
                v-if="item.isShow ? item.isShow[scope.$index] : true"
              >
                <el-button
                  v-if="buttonVisibleFunc(item.functionKey, scope.row)"
                  @click="clickButton(item.functionKey, scope.row)"
                  :key="item.value"
                  style="margin: 0 5px"
                  size="mini"
                  type="text"
                >
                  <span :style="'color:' + getColorFromRow(scope.row, item)">{{ item.label }}</span>
                </el-button>
              </div>
            </template>
          </template>
        </el-table-column>
        <el-table-column
          v-for="(item, index) in header"
          :width="item.width"
          :label="item.label"
          :prop="item.prop"
          :key="index"
          sortable
          :column-key="index.toString()"
          :render-header="renderHeader"
          align="center"
        >
          <template slot-scope="scope">
            <el-button
              v-if="!!item.isButton"
              @click="clickButton(item.functionKey, scope.row)"
              style="font-size: inherit; color: inherit"
              size="mini"
              type="text"
            >
              {{ scope.row[item.prop] }}
            </el-button>
            <span v-else-if="!!item.isImage">
              <img :src="scope.row[item.prop]" alt="" class="img-box" v-if="scope.row[item.prop]" />
            </span>
            <div
              v-else-if="item.label == '是否录入'"
              :class="[
                scope.row.extrasRecorded == '0'
                  ? 'greyStatus'
                  : scope.row.extrasRecorded == '1' && scope.row.serviceStatus == '诊断中'
                  ? 'redStatus'
                  : scope.row.extrasRecorded == '1' && scope.row.serviceStatus == '诊断结束'
                  ? 'greenStatus'
                  : ''
              ]"
              class="colorStatus"
            ></div>
            <div v-else-if="item.label == '服务简介'">
              <el-tooltip class="item" effect="dark" placement="right">
                <div slot="content" style="width: 200px">{{ scope.row.description }}</div>
                <span>{{ scope.row.descriptionStr }}</span>
              </el-tooltip>
            </div>
            <div v-else-if="item.label == '服务内容'">
              <el-tooltip class="item" effect="dark" placement="right">
                <div slot="content" style="width: 200px">{{ scope.row.declaration }}</div>
                <span>{{ scope.row.declarationStr }}</span>
              </el-tooltip>
            </div>
            <ex-slot
              v-else-if="item.isRender"
              :render="item.render"
              :row="scope.row"
              :index="scope.$index"
              :column="item"
            />
            <span v-else>{{ scope.row[item.prop] }}</span>
          </template>
        </el-table-column>
      </el-table>
    </el-row>
    <el-row v-if="showPageInfo" style="margin-top: 10px" align="right">
      <el-pagination
        :page-sizes="pageSizes"
        @current-change="pageJumpTo"
        @size-change="sizeChange"
        :current-page="pageInfo.page"
        :page-size="pageInfo.size"
        :total="pageInfo.total"
        style="text-align: center; margin-top: 12px"
        layout="sizes, prev, pager, next, total"
      >
      </el-pagination>
    </el-row>
  </div>
</template>

<script>
let exSlot = {
  functional: true,
  props: {
    row: Object,
    render: Function,
    index: Number,
    column: {
      type: Object,
      default: null
    }
  },
  render: (h, data) => {
    const params = {
      row: data.props.row,
      index: data.props.index
    }
    if (data.props.column) params.column = data.props.column
    return data.props.render(h, params)
  }
}
const IdSet = new Set()
// 默认表格按钮显示判断方法
const defaultButtonVisibleFunc = function(func, rowData) {
  return true
}
// 默认表格单元格样式方法
const defaultCellStyleFunc = function() {
  return {
    padding: '3px 0',
    'border-right': '1px solid #ffffff',
    'font-size': '14px'
  }
}

export default {
  name: 'BaseTable',
  components: { exSlot },
  props: {
    data: Array,
    header: Array,
    operation: Array,
    pageInfo: Object,
    pageSizes: Array,
    selected: Boolean,
    buttonVisibleFunc: {
      type: Function,
      default: defaultButtonVisibleFunc
    },
    cellStyleFunc: {
      type: Function,
      default: defaultCellStyleFunc
    }
  },
  data() {
    return {
      multipleSelection: [],
      selectRows: [],
      row: [],
      dragState: {
        startIndex: -1, // 拖动起始元素的index
        endIndex: -1, // 拖动结束元素的index
        afterMoveIndex: -1, // 拖动后元素的index
        dragging: false, // 是否正在拖动
        direction: null, // 拖动方向
        moveTableOutsideBack: false // 拖出到table外之后又拖回来
      }
    }
  },
  computed: {
    showPageInfo() {
      return !this.pageInfo.hide
    }
  },
  methods: {
    getColorFromRow(row, item) {
      if (row && row.receiveWithoutSignInCount > 0 && item.label == '快递') {
        return 'red'
      } else if (item.color) {
        return item.color
      }
      return '#266EFF'
    },
    // 选择行
    handleSelect(selection, row) {
      // 添加的 index 为数据列表中的位置信息
      if (IdSet.has(row.index)) {
        IdSet.delete(row.index)
      } else {
        IdSet.add(row.index)
      }
      this.$emit('selectedRow', IdSet)
    },
    // 全选
    handleSelectAll() {
      for (let i = 0; i < this.data.length; i++) {
        IdSet.add(i)
      }
      // console.log('SelectAll', selection);
      this.$emit('selectedRow', IdSet)
    },
    // 选择行变化
    handleSelectionChange(selection) {
      // console.log('handleSelectionChange', selection);
      this.$emit('selectionChange', selection)
    },
    // 表格列宽度改变
    handleColumnChange(newWidth, oldWidth, column, event) {
      // console.log('ColumnChange', newWidth, oldWidth, column, event);
      this.$emit('columnChange', newWidth, oldWidth, column, event)
    },
    // 按钮点击
    clickButton(functionKey, row) {
      this.$emit('handleClick', functionKey, row)
    },
    // 真实序号计算（计算分页影响）
    getIndex(index) {
      return (this.pageInfo.page - 1) * this.pageInfo.size + index + 1
    },
    // 页数跳转
    pageJumpTo(page) {
      this.$emit('pageJumpTo', page)
    },
    // 每页显示数量改变
    sizeChange(size) {
      this.$emit('sizeChange', size)
    },
    // drag_table在渲染表头时调用
    renderHeader(h, { column, $index }) {
      let item = this.header[$index - 2]

      if (item && item.tooltip) {
        return h(
          'span',
          {
            class: ['thead-cell'],
            style: { cursor: 'move' },
            on: {
              mousedown: $event => {
                this.handleMouseDown($event, column)
              },
              mouseup: $event => {
                this.handleMouseUp($event, column)
              },
              mousemove: $event => {
                this.handleMouseMove($event, column)
              },
              mouseover: $event => {
                this.handlemouseover($event, column)
              }
            }
          },
          [
            h('el-tooltip', { props: item.tooltip }, [
              h('template', { slot: 'content' }, this.$slots[item.tooltip.name]),
              h('span', [h('span', column.label)])
            ])
          ]
        )
      }
      // 这里可以根据$index的值来对自身需求进行修改，
      else
        return h(
          'span',
          {
            class: ['thead-cell'],
            style: {
              cursor: 'move'
            },
            on: {
              mousedown: $event => {
                this.handleMouseDown($event, column)
              },
              mouseup: $event => {
                this.handleMouseUp($event, column)
              },
              mousemove: $event => {
                this.handleMouseMove($event, column)
              },
              mouseover: $event => {
                this.handlemouseover($event, column)
              }
            }
          },
          [
            h('span', [
              // 给每个表头添加icon 可以不需要
              // h('span', {
              //     class: $index === 0 ? 'el-icon-star-off' : $index === 1 ? 'el-icon-time' : $index === 2 ? 'el-icon-location' : '',
              // }),
              h('span', column.label)
            ])
            // 给每个表头添加一个class=virtual 是画虚线的类名。
            // h('span', {
            //     'class': ['virtual']
            // })
          ]
        )
    },
    // 按下鼠标开始拖动 设置列的背景色
    handleMouseDown(e, column) {
      // 判断是鼠标左键
      if (e.button === 0) {
        this.dragState.dragging = true
        this.dragState.startIndex = parseInt(column.columnKey)
        console.log(`开始移动的位置 ${this.dragState.startIndex}`)
        // 给当前要拖动列的th设置class
        document.querySelectorAll('.drag_table table thead tr th')[
          this.dragState.startIndex
        ].className += ' ' + 'dragging_column'
        // 给拖动时的虚拟容器添加宽高
        let table = document.getElementsByClassName('drag_table')[0]
        let virtual = document.getElementsByClassName('virtual')
        // 设置新插入的span.virtual的标签 每一列的宽度、高度
        for (let item of virtual) {
          item.style.height = table.clientHeight - 1 + 'px'
          item.style.width = item.parentElement.parentElement.clientWidth + 'px'
        }
        this.dragState.moveTableOutsideBack = false
      }
    },
    // 拖动中
    handleMouseMove(e, column) {
      // 判断是鼠标左键
      if (e.button === 0) {
        if (this.dragState.dragging) {
          let currentIndex = parseInt(column.columnKey) // 拖动的当前列index
          console.log(`移动到了${currentIndex}`)
          if (currentIndex !== this.dragState.startIndex) {
            this.dragState.direction =
              currentIndex - this.dragState.startIndex < 0 ? 'left' : 'right' // 判断拖动方向
            this.dragState.afterMoveIndex = currentIndex
          } else {
            this.dragState.direction = null
          }
        } else {
          return false
        }
      }
    },
    // 鼠标悬浮
    handlemouseover(e, column) {
      if (column.label == '扫描确认') {
        console.log('colum1111111111111111', column)
        return '<span>{column.label+11}</span>'
      }
    },
    // 鼠标放开结束拖动
    handleMouseUp(e, column) {
      // 判断是鼠标左键
      if (e.button === 0) {
        // 拖出当前table外之后又拖回来，不再进行易位操作（拖出去时已处理）
        if (this.dragState.moveTableOutsideBack) {
          return false
        } else {
          this.dragState.endIndex = parseInt(column.columnKey) // 记录结束列index
          console.log(`结束移动的位置 ${this.dragState.endIndex}`)
          if (this.dragState.startIndex !== this.dragState.endIndex) {
            this.dragColumn(this.dragState)
          }
          this.finishDragInit()
        }
      }
    },
    // 拖动到当前table之外的处理
    moveTableOutside() {
      if (this.dragState.dragging) {
        this.dragState.endIndex = this.dragState.startIndex
        console.log(`已移动到table外，结束移动的位置 ${this.dragState.endIndex}`)
        if (this.dragState.startIndex !== this.dragState.endIndex) {
          this.dragColumn(this.dragState)
        }
        this.finishDragInit()
        this.dragState.moveTableOutsideBack = true
      }
    },
    // 拖动易位
    dragColumn({ startIndex, endIndex, direction }) {
      console.log(`从${startIndex}移动到了${endIndex}`)
      // 排除掉鼠标点击table外面，然后拖入进table报错
      if (startIndex < 0) {
        return
      }
      // 判断是向左移动还是向右移动
      // 把移动的列插在某个列前面或者后面，然后在删除移动的列
      if (direction === 'left') {
        this.header.splice(endIndex, 0, this.header[startIndex])
        this.header.splice(startIndex + 1, 1)
      } else {
        this.header.splice(endIndex + 1, 0, this.header[startIndex])
        this.header.splice(startIndex, 1)
      }
      if (this.whichPageHeader == 'scanMatchedHeader') {
        localStorage.setItem('scanMatchedHeader', JSON.stringify(this.header))
      }
    },
    // 拖动完成后的初始化
    finishDragInit() {
      // 给当前要拖动列的th取消class
      for (var item of document.querySelectorAll('.drag_table table thead tr th')) {
        item.className = String(item.className)
          .split('dragging_column')
          .join('')
      }
      // 再次初始化拖动状态
      this.dragState = {
        startIndex: -1,
        endIndex: -1,
        afterMoveIndex: -1,
        dragging: false,
        direction: null,
        moveTableOutsideBack: false
      }
    },
    // 动态给表头单元格添加 class，实现拖动中的虚线效果
    /* 
        这个监听在table渲染的时候会执行一遍。 
        然后还会有两个条件会触发执行：
        1. 绑定的数据发生变化的时候(即为表格内容变化就触发)。header变化触发header-cell-class-name，表格数据变化触发cell-class-name.
        2. return返回值 如果绑定了data,如果此data变化也会触发执行。相当于对这个data进行了监听随之触发这个方法。
    */
    headerCellClassName({ column, columnIndex }) {
      return columnIndex === this.dragState.afterMoveIndex
        ? `drag_active_${this.dragState.direction}`
        : ''
    },
    // 动态给表头单元格th添加class，实现拖动中的背景
    cellClassName({ column, columnIndex }) {
      return columnIndex === this.dragState.startIndex ? `dragging_column` : ''
    }
  }
}
</script>

<style scoped>
.colorStatus {
  width: 10px;
  height: 10px;
  border-radius: 20px;
  margin: 0 auto;
}
.greenStatus {
  background-color: green;
}
.redStatus {
  background-color: red;
}
.greyStatus {
  background-color: #000;
}
.content-board {
  padding: 20px;
  background: #ffffff;
}
.item {
  margin-top: 10px;
}
.img-box {
  width: 100px;
  height: 100px;
  vertical-align: middle;
}
</style>
<style>
.drag_table th {
  cursor: move;
}
.virtual {
}
.drag_active_left .virtual {
}
.drag_active_right .virtual {
}
/* 
        给选中要拖动的列添加背景色，如果在完整项目内部的组件，所以这个组件的style，不能加scoped,否则添加不上样式
        如果使用了sass或者less,可以加scoped 然后在用特殊手法处理样式
    */
.dragging_column {
  background-color: #fff;
}
</style>
